﻿using System;
using MathService.Vectors;

namespace MathService.Interpolation
{
	public class Lagramge
	{
		private delegate void Initializator(double[] X, double[] Y);


		public event EventHandler OnInitialized;

		public void Invoke_OnInitialized(EventArgs Args)
		{
			var lv_Handler = OnInitialized;
			if(lv_Handler != null)
				lv_Handler(this, Args);
		}
		private void Invoke_OnInitialized()
		{
			Invoke_OnInitialized(EventArgs.Empty);
		}

		private Polynom f_Polynom;
		private IAsyncResult f_InitializationResult;

		public Polynom P { get { return f_Polynom; } set { f_Polynom = value; } }
		public bool Initialized { get { return f_InitializationResult.IsCompleted; } }

		public double this[double x] { get { return Value(x); } }

		public Lagramge(double[] X, double[] Y)
		{
			f_InitializationResult = ((Initializator)Initialize).BeginInvoke(X, Y,
				OnInitializationComplite, null);
		}

		public Lagramge(params Vector2D[] P)
		{
			var x = new double[P.Length];
			var y = new double[P.Length];
			for(var i = 0; i < P.Length; i++) { x[i] = P[i].X; y[i] = P[i].Y; }
			f_InitializationResult = ((Initializator)Initialize).BeginInvoke(x, y,
				OnInitializationComplite, null);
		}

		private void Initialize(double[] X, double[] Y)
		{
			var lv_Powers = new double[X.Length - 1];
			var lv_N = Y.Length;
			for(var n = 0; n < lv_N; n++)
			{
				var x = new double[X.Length - 1];
				for(int i = 0, j = 0; i < X.Length; i++)
					if(i != n) x[j++] = X[i];
				var lv_Polynom = Polynom.GetPolynom(x);
				var lv_C = Y[n] / lv_Polynom.Value(X[n]);
				var powers = lv_Polynom.Coefficients;
				powers = Array.ConvertAll(powers, p => p*lv_C);
				for(var i = 0; i < powers.Length; i++)
					lv_Powers[i + 1] += powers[i];
			}
			f_Polynom = new Polynom(lv_Powers);
		}

		private void OnInitializationComplite(IAsyncResult Result)
		{
			Invoke_OnInitialized();
		}

		public double Value(double x)
		{
			if(!Initialized) f_InitializationResult.AsyncWaitHandle.WaitOne();
			return f_Polynom.Value(x);
		}
	}
}
